//
//  OperationWorker.m
//  GCD_Lab0
//
//  Created by Xu Deheng on 12-4-1.
//  Copyright (c) 2012年 __MyCompany__ All rights reserved.
//

#import "URLConnectionOperation.h"

@interface URLConnectionOperation()
- (void)buildPostBody;
- (void)startAsynConnection;
- (void)startSynConnection;
@end

@implementation URLConnectionOperation
@synthesize url;
@synthesize connection;
@synthesize operationDelegate;
@synthesize httpMethod;
@synthesize params;
@synthesize headFields;
@synthesize loadedData;

static NSOperationQueue *connectionQueue = nil;

+ (NSOperationQueue *)mainQueue
{
    return [NSOperationQueue mainQueue];
}

+ (NSOperationQueue *)networkQueue
{
    if (!connectionQueue) {
        connectionQueue = [NSOperationQueue new];
    }
    return connectionQueue;
}

+ (void)initialize
{
    if (self == [URLConnectionOperation class]) {
        if (connectionQueue == nil) {
            connectionQueue = [NSOperationQueue new];
        }
    }
}

- (id)init
{
    self = [super init];
    if (self) {
        _isConcurrent = NO;
        canLoadData_ = YES;
        self.httpMethod = HTTP_GET_METHOD;
        headFields = [[NSMutableDictionary alloc] initWithCapacity:8];
        params = [[NSMutableArray alloc] initWithCapacity:8];
    }
    return self;
}

- (id)initWithURL:(NSURL *)aUrl
{
    self = [self init];
    if (self) {
        self.url = aUrl;
    }
    return self;
}

- (id)initWithURL:(NSURL *)aUrl canLoadData:(BOOL)loadData
{
    self = [self initWithURL:aUrl];
    if (self) {
        canLoadData_ = loadData;
    }
    return self;
}

- (void)dealloc
{
    NSLog(@"%s", __func__);
    operationDelegate = nil;
    [url release];
    [connection cancel];
    [connection release];
    [dataBuffer release];
    [httpMethod release];
    [params release];
    [headFields release];
    [super dealloc];
}

- (void)buildPostBody
{
    if ([httpMethod isEqualToString:HTTP_POST_METHOD]) {

    }
}

- (NSData *)loadedData
{
    return dataBuffer;
}

#pragma mark - synchronizing method
//- (void)main
//{
//    NSLog(@"%s", __func__);
//    [self startConnection];
//}

- (void)startSynConnection
{
    NSMutableURLRequest *request = [[NSMutableURLRequest requestWithURL:self.url] retain];
    
    [request setHTTPMethod:self.httpMethod];
    
    if (params.count > 0) {
        if ([httpMethod isEqualToString:HTTP_GET_METHOD]) {
            request.URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/?%@", self.url.absoluteString, [[XUtils instance] httpParamsStringByArray:params]]];
        }else if ([httpMethod isEqualToString:HTTP_POST_METHOD]) {
            request.HTTPBody = [[[XUtils instance] httpParamsStringByArray:params] dataUsingEncoding:NSUTF8StringEncoding];
        }
    }
    if (headFields) {
        [request setAllHTTPHeaderFields:headFields];
    }

    if (nil == dataBuffer) {
        dataBuffer = [[NSMutableData alloc] initWithCapacity:DATA_KILOBYTES];
    }
    
    NSURLResponse *resp_ = nil;
    NSError *err_ = nil;

    _isExecuting = YES;
    
    NSData *data_ = [NSURLConnection sendSynchronousRequest:request returningResponse:&resp_ error:&err_];
    
    if (data_) {
        [dataBuffer appendData:data_];
    }
    if (nil == err_) {
        if (resp_) {
            if ([resp_ isKindOfClass:[NSHTTPURLResponse class]]) {
                NSLog(@"response :%@", [(NSHTTPURLResponse*)resp_ allHeaderFields]);
            }
        }
    }else {
        if (operationDelegate && [operationDelegate respondsToSelector:@selector(connectionOperation:didFailedWithError:)]) {
            [operationDelegate connectionOperation:self didFailedWithError:err_];
        }
    }
    
    //NSLog(@"request url :%@", [NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", self.url.absoluteString, [[XUtils instance] httpParamsStringByDictionary:params]]]);
    
    [request release];
    
    _isExecuting = NO;
    _isFinished = YES;
}

#pragma mark - asynchronizing method

- (void)startAsynConnection
{
#if !RUNLOOP_MODE___
    if (![NSThread currentThread].isMainThread) {
        [self performSelectorOnMainThread:@selector(startConnection) withObject:nil waitUntilDone:NO];
        return;
    }
#endif
    NSMutableURLRequest *request = [[NSMutableURLRequest requestWithURL:self.url] retain];
    
    [request setHTTPMethod:self.httpMethod];
    
    if (params.count > 0) {
        if ([httpMethod isEqualToString:HTTP_GET_METHOD]) {
            request.URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/?%@", self.url.absoluteString, [[XUtils instance] httpParamsStringByArray:params]]];
        }else if ([httpMethod isEqualToString:HTTP_POST_METHOD]) {
            request.HTTPBody = [[[XUtils instance] httpParamsStringByArray:params] dataUsingEncoding:NSUTF8StringEncoding];
        }
    }
    
    if (headFields) {
        [request setAllHTTPHeaderFields:headFields];
    }
    
    connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    [self willChangeValueForKey:@"isExecuting"];
    _isExecuting = YES;
    [self didChangeValueForKey:@"isExecuting"];
        
    [request release];
    
#if RUNLOOP_MODE___
    //NSLog(@"connection runloop mode!");
    while (!_isFinished && !self.isCancelled) {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }
    //NSLog(@"connection runloop mode over!");
#endif
    
}

- (void)main
{
    
}

- (void)start
{
    //NSLog(@"%s", __func__);
    [self startAsynConnection];
    //[self main];
}

- (void)cancel
{
    [super cancel];
    if (connection) {
        if (_isExecuting) {
            [connection cancel];
        }
        [connection release];
        connection = nil;
    }
    [self willChangeValueForKey:@"isFinished"];
    [self willChangeValueForKey:@"isExecuting"];
    _isFinished = YES;
    _isExecuting = NO;
    [self didChangeValueForKey:@"isFinished"];
    [self didChangeValueForKey:@"isExecuting"];

}

- (BOOL)isConcurrent
{
    //NSLog(@"%s", __func__);
    return _isConcurrent;
}

- (BOOL)isExecuting
{
    //NSLog(@"%s", __func__);
    return _isExecuting;
}

- (BOOL)isFinished
{
    //NSLog(@"%s", __func__);
    return _isFinished;
}

#pragma mark - connection

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSHTTPURLResponse *httpResponse = nil;
    if (canLoadData_) {
        //clear history data buffer
        if (dataBuffer) {
            [dataBuffer release];
            dataBuffer = nil;
        }
        if (nil == dataBuffer) {
            dataBuffer = [[NSMutableData alloc] initWithCapacity:DATA_KILOBYTES];
        }
    }
    
    if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
        httpResponse = (NSHTTPURLResponse *)response;
    }
    
    if (httpResponse) {
        httpStatusCode = httpResponse.statusCode;
        /*
         Doing sth. according to the http status code.
         */
        if (httpStatusCode == 200) {
            
        }
    }
    if (operationDelegate && [operationDelegate respondsToSelector:@selector(connectionOperation:didReceivedResponse:)]) {
        [operationDelegate connectionOperation:self didReceivedResponse:response];
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    if (canLoadData_ && dataBuffer) {
        [dataBuffer appendData:data];
    }
    if (operationDelegate && [operationDelegate respondsToSelector:@selector(connectionOperation:didReveivedData:)]) {
        [operationDelegate connectionOperation:self didReveivedData:data];
    }
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    //NSLog(@"%s;", __func__);
    [self willChangeValueForKey:@"isFinished"];
    [self willChangeValueForKey:@"isExecuting"];
    _isExecuting = NO;
    _isFinished = YES;
    [self didChangeValueForKey:@"isFinished"];
    [self didChangeValueForKey:@"isExecuting"];
    
    if (operationDelegate) {
        if (canLoadData_ && [operationDelegate respondsToSelector:@selector(connectionOperation:DidFinishedLoading:)] && dataBuffer) {
            [operationDelegate connectionOperation:self DidFinishedLoading:dataBuffer];
        }
        if ([operationDelegate respondsToSelector:@selector(connectionOperationDidFinishedLoading:)]) {
            [operationDelegate connectionOperationDidFinishedLoading:self];
        }
    }
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    //NSLog(@"%s;", __func__);
    [self willChangeValueForKey:@"isFinished"];
    [self willChangeValueForKey:@"isExecuting"];
    _isExecuting = NO;
    _isFinished = YES;
    [self didChangeValueForKey:@"isFinished"];
    [self didChangeValueForKey:@"isExecuting"];
    
    if (operationDelegate) {
        if ([operationDelegate respondsToSelector:@selector(connectionOperation:didFailedWithError:)]) {
            [operationDelegate connectionOperation:self didFailedWithError:error];
        }
    }
}

- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response
{
    //NSLog(@"willSendRequest :%@", request.allHTTPHeaderFields);
    //NSLog(@"directResponse :%@", response);
    return request;
}

- (void)addParamValue:(id)value forKey:(NSString *)key
{
    if (params == nil) {
        params = [[NSMutableArray alloc] initWithCapacity:8];
    }
    [params setValue:value forKey:key];
}

- (void)startSynchronized
{
    [self startSynConnection];
}

- (void)startAsynchronized
{
    [connectionQueue setSuspended:YES];
    [connectionQueue addOperation:self];
    [connectionQueue setSuspended:NO];
}

@end


@implementation NSArray (URLConnectionOperation)

- (URLConnectionOperation *)urlConnectionOperationAtIndex:(NSUInteger)aIndex
{
    URLConnectionOperation *op = [self objectAtIndex:aIndex];
    if ([op isKindOfClass:[URLConnectionOperation class]]) {
        return op;
    }
    return nil;
}

@end


